﻿#pragma once

#include "../box/service_box.hh"
#include "../detail/lang_impl.hh"
#include "../http/http_call.hh"
#include "../util/box_std_allocator.hh"
#include "../util/object_pool.hh"

#include <ctime>
#include <memory>
#include <string>
#include <unordered_map>

namespace kratos {
namespace http {
class HttpBaseImpl;
}
} // namespace kratos

namespace kratos {
namespace service {

class CommandImpl;
class ServiceBox;

/**
 * 外部命令管理.
 */
class CommandManager {
  using CommandMap = std::unordered_map<
      std::string,
      CommandImpl*,
      std::hash<std::string>,
      std::equal_to<std::string>,
      Allocator<std::pair<const std::string, CommandImpl*>>
  >;

  unique_pool_ptr<http::HttpBaseImpl> http_{nullptr}; ///< HTTP服务

  CommandMap           command_map_;       ///< 注册的命令列表
  CommandMap           path_map_;          ///< 注册的路径
  service::ServiceBox* box_{nullptr};      ///< 服务容器
  std::string          host_{"127.0.0.1"}; ///< 监听地址
  int                  port_{6889};        ///< 默认监听端口
  bool                 enable_{true};      ///< 是否开启
  std::string          listen_address_;    ///< 监听地址{ip:port}

public:
  /**
   * 构造函数.
   *
   * \param box 服务容器指针
   */
  CommandManager(service::ServiceBox *box);
  /**
   * 析构.
   *
   */
  ~CommandManager();
  /**
   * 启动.
   *
   * \return true或false
   */
  auto start() -> bool;
  /**
   * 关闭.
   *
   * \return
   */
  auto stop() -> void;
  /**
   * 在逻辑主循环内调用.
   *
   * \param ms 时间戳，毫秒
   * \return
   */
  auto update(std::time_t ms) -> void;
  /**
   * 添加一个命令的处理.
   *
   * \param name 命令名
   * \param command 命令处理器
   * \return true或false
   */
  auto add_command(const std::string &name, CommandImpl *command) -> bool;
  /**
   * 添加一个路径的处理.
   *
   * \param path 路径
   * \param command 命令处理器
   * \return true或false
   */
  auto add_path(const std::string& path, CommandImpl* command) -> bool;
  /**
   * 删除命令处理器.
   *
   * \param name 命令名
   * \return
   */
  auto del_command(const std::string &name) -> void;
  /**
   * 删除路径处理器.
   *
   * \param path 路径名
   * \return
   */
  auto del_path(const std::string& path) -> void;
  /**
   * 获取服务器容器指针
   */
  auto get_box() -> ServiceBox *;
  /**
   * 是否开启.
   *
   * \return
   */
  auto is_enable() -> bool;
  /**
   * 获取监听的地址.
   *
   * \return
   */
  auto get_host() -> const std::string &;
  /**
   * 获取监听端口.
   *
   * \return
   */
  auto get_port() -> int;
  /**
   * 加载配置.
   *
   * \return true或false
   */
  auto load_config() -> bool;

private:
  /**
   * 日志写入.
   *
   * \param lang_id 语言ID
   * \param level 日志等级
   * \param ...args 日志参数
   * \return
   */
  template <typename... ARGS>
  auto write_log(lang::LangID lang_id, int level, ARGS... args) -> void {
    if (box_) {
      box_->write_log(lang_id, level, args...);
    }
  }
  /**
   * 启动HTTP监听器并等待.
   *
   * \return true或false
   */
  auto wait_request() -> bool;
  /**
   * 检查请求.
   *
   * \param request 请求
   * \param response 响应
   * \param command 命令
   * \return 命令处理器
   */
  auto check_request(http::HttpCallPtr request, http::HttpCallPtr response,
                     std::string &command) -> kratos::service::CommandImpl *;
};

} // namespace service
} // namespace kratos
